﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;

namespace VivendoByteToolkit.Helpers
{
    public class DragAndDropCommandHelper
    {
        private static ListViewBase DragAndDropLastSource;

        #region Dependencies Property
        public static readonly DependencyProperty DragItemsProperty =
            DependencyProperty.RegisterAttached("DragItems",
            typeof(object),
            typeof(DragAndDropCommandHelper),
            new PropertyMetadata(null)
            );

        public static readonly DependencyProperty SourceCommandProperty =
            DependencyProperty.RegisterAttached("SourceCommand",
            typeof(ICommand),
            typeof(DragAndDropCommandHelper),
            new PropertyMetadata(null,
            new PropertyChangedCallback(sourceCommandChanged))
            );

        public static readonly DependencyProperty TargetCommandProperty =
            DependencyProperty.RegisterAttached("TargetCommand",
            typeof(ICommand),
            typeof(DragAndDropCommandHelper),
            new PropertyMetadata(null,
            new PropertyChangedCallback(targetCommandChanged))
            );

        public static readonly DependencyProperty OverCommandProperty =
            DependencyProperty.RegisterAttached("OverCommand",
            typeof(ICommand), typeof(DragAndDropCommandHelper),
            new PropertyMetadata(null,
            new PropertyChangedCallback(overCommandChanged))
            );
        #endregion

        #region [Get|Set]SourceCommand
        public static ICommand GetSourceCommand(ListViewBase element)
        {
            return (ICommand)element.GetValue(SourceCommandProperty);
        }

        public static void SetSourceCommand(ListViewBase element, ICommand value)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }
            element.SetValue(SourceCommandProperty, value);
        }
        #endregion

        #region [Get|Set]TargetCommand
        public static ICommand GetTargetCommand(DependencyObject element)
        {
            return (ICommand)element.GetValue(TargetCommandProperty);
        }

        public static void SetTargetCommand(DependencyObject element, ICommand value)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }
            element.SetValue(TargetCommandProperty, value);
        }
        #endregion

        #region [Get|Set]OverCommand
        public static ICommand GetOverCommand(DependencyObject element)
        {
            return (ICommand)element.GetValue(OverCommandProperty);
        }

        public static void SetOverCommand(DependencyObject element, ICommand value)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }
            element.SetValue(OverCommandProperty, value);
        }
        #endregion

        private static void sourceCommandChanged(DependencyObject d, object value)
        {
            var element = d as ListViewBase;
            var cmd = element.GetValue(SourceCommandProperty);

            if (cmd != null)
            {
                element.DragItemsStarting += element_DragItemsStarting;
            }
            else
            {
                element.DragItemsStarting -= element_DragItemsStarting;
            }
        }

        private static void overCommandChanged(DependencyObject d, object value)
        {
            var element = d as FrameworkElement;
            var cmd = element.GetValue(OverCommandProperty);

            if (cmd != null)
            {
                element.AllowDrop = true;
                element.DragOver += element_DragOver;
            }
            else
            {
                element.AllowDrop = false;
                element.DragOver -= element_DragOver;
            }
        }

        static void element_DragOver(object sender, DragEventArgs e)
        {
            DependencyObject dp = sender as DependencyObject;
            var command = dp.GetValue(OverCommandProperty);

            if (command != null)
            {
                var parameter = DragAndDropCommandHelper.DragAndDropLastSource.GetValue(DragItemsProperty);
                ICommand cmd = command as ICommand;

                if (cmd.CanExecute(parameter))
                {
                    cmd.Execute(parameter);
                }
            }
        }

        static void element_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
        {
            ListViewBase dp = sender as ListViewBase;
            var command = dp.GetValue(SourceCommandProperty);
            DragAndDropCommandHelper.DragAndDropLastSource = dp;
            dp.SetValue(DragItemsProperty, e.Items[0]);

            if (command != null)
            {
                //var parameter = dp.GetValue(SourceCommandParameterProperty);
                var parameter = e.Items[0];
                ICommand cmd = command as ICommand;

                if (cmd.CanExecute(parameter))
                {
                    cmd.Execute(parameter);
                }
            }
        }

        private static void targetCommandChanged(DependencyObject d, object value)
        {
            FrameworkElement element = d as FrameworkElement;
            var cmd = element.GetValue(TargetCommandProperty);

            if (cmd != null)
            {
                element.AllowDrop = true;
                element.Drop += element_Drop;
            }
            else
            {
                element.AllowDrop = false;
                element.Drop -= element_Drop;
            }
        }

        static void element_Drop(object sender, DragEventArgs e)
        {
            DependencyObject dp = sender as DependencyObject;
            var command = dp.GetValue(TargetCommandProperty);

            if (command != null)
            {
                //var parameter = dp.GetValue(TargetCommandParameterProperty);
                var parameter = DragAndDropCommandHelper.DragAndDropLastSource.GetValue(DragItemsProperty);
                ICommand cmd = command as ICommand;
                
                if (cmd.CanExecute(parameter))
                {
                    cmd.Execute(parameter);
                }
            }
        }
    }
}